﻿Imports System
Imports System.CodeDom
Imports System.Collections.Generic
Imports System.Globalization
Imports System.Reflection
Imports System.Workflow.ComponentModel.Compiler

Namespace System.Workflow.Activities.Rules
    Public MustInherit Class RuleReadWriteAttribute
        Inherits RuleAttribute
        ' Methods
        Protected Sub New(ByVal path As String, ByVal target As RuleAttributeTarget)
            Me.attributeTarget = target
            Me.attributePath = path
        End Sub

        Friend Sub AnalyzeReadWrite(ByVal analysis As RuleAnalysis, ByVal targetExpression As CodeExpression, ByVal targetQualifier As RulePathQualifier, ByVal argumentExpressions As CodeExpressionCollection, ByVal parameters As ParameterInfo(), ByVal attributedExpressions As List([Of] CodeExpression))
            If String.IsNullOrEmpty(Me.attributePath) Then
                If (Me.attributeTarget = RuleAttributeTarget.This) Then
                    attributedExpressions.Add(targetExpression)
                ElseIf (Me.attributeTarget = RuleAttributeTarget.Parameter) Then
                    Dim i As Integer
                    For i = 0 To argumentExpressions.Count - 1
                        attributedExpressions.Add(argumentExpressions.Item(i))
                    Next i
                End If
            Else
                Dim attributePath As String = Me.attributePath
                Dim isRead As Boolean = Not analysis.ForWrites
                Dim forWrites As Boolean = analysis.ForWrites
                If (Me.attributeTarget = RuleAttributeTarget.This) Then
                    Dim str2 As String = "this/"
                    If attributePath.StartsWith(str2, StringComparison.Ordinal) Then
                        attributePath = attributePath.Substring(str2.Length)
                    End If
                    RuleExpressionWalker.AnalyzeUsage(analysis, targetExpression, isRead, forWrites, New RulePathQualifier(attributePath, targetQualifier))
                    attributedExpressions.Add(targetExpression)
                ElseIf (Me.attributeTarget = RuleAttributeTarget.Parameter) Then
                    Dim paramName As String = Nothing
                    Dim index As Integer = attributePath.IndexOf("/"c)
                    If (index >= 0) Then
                        paramName = attributePath.Substring(0, index)
                        attributePath = attributePath.Substring((index + 1))
                    Else
                        paramName = attributePath
                        attributePath = Nothing
                    End If
                    Dim info As ParameterInfo = Array.Find([Of] ParameterInfo)(parameters, Function (ByVal p As ParameterInfo) 
                        Return (p.Name = paramName)
                    End Function)
                    If (Not info Is Nothing) Then
                        Dim qualifier As RulePathQualifier = If(String.IsNullOrEmpty(attributePath), Nothing, New RulePathQualifier(attributePath, Nothing))
                        Dim count As Integer = (info.Position + 1)
                        If (info.Position = (parameters.Length - 1)) Then
                            count = argumentExpressions.Count
                        End If
                        Dim j As Integer
                        For j = info.Position To count - 1
                            Dim expression As CodeExpression = argumentExpressions.Item(j)
                            RuleExpressionWalker.AnalyzeUsage(analysis, expression, isRead, forWrites, qualifier)
                            attributedExpressions.Add(expression)
                        Next j
                    End If
                End If
            End If
        End Sub

        Friend Overrides Function Validate(ByVal validation As RuleValidation, ByVal member As MemberInfo, ByVal contextType As Type, ByVal parameters As ParameterInfo()) As Boolean
            Dim error As ValidationError = Nothing
            If String.IsNullOrEmpty(Me.attributePath) Then
                Return True
            End If
            Dim strArray As String() = Me.attributePath.Split(New Char() { "/"c })
            Dim str2 As String = strArray(0)
            Dim num As Integer = 0
            If (Me.attributeTarget = RuleAttributeTarget.This) Then
                If (str2 = "this") Then
                    num += 1
                End If
            Else
                Dim flag2 As Boolean = False
                Dim j As Integer
                For j = 0 To parameters.Length - 1
                    Dim info As ParameterInfo = parameters(j)
                    If (info.Name = str2) Then
                        flag2 = True
                        contextType = info.ParameterType
                        Exit For
                    End If
                Next j
                If Not flag2 Then
                    [error] = New ValidationError(String.Format(CultureInfo.CurrentCulture, Messages.InvalidRuleAttributeParameter, New Object() { str2, member.Name }), 420)
                    [error].UserData.Item("ErrorObject") = Me
                    validation.AddError([error])
                    Return False
                End If
                num += 1
            End If
            Dim length As Integer = strArray.Length
            Dim str3 As String = strArray((length - 1))
            If (String.IsNullOrEmpty(str3) OrElse (str3 = "*")) Then
                length -= 1
            End If
            Dim fieldType As Type = contextType
            Dim i As Integer
            For i = num To length - 1
                If Not (strArray(i) = "*") Then
                    goto Label_0171
                End If
                [error] = New ValidationError(Messages.InvalidWildCardInPathQualifier, &H195)
                [error].UserData.Item("ErrorObject") = Me
                validation.AddError([error])
                Return False
            Label_0168:
                fieldType = fieldType.GetElementType
            Label_0171:
                If fieldType.IsArray Then
                    goto Label_0168
                End If
                Dim bindingAttr As BindingFlags = (BindingFlags.FlattenHierarchy Or (BindingFlags.Public Or (BindingFlags.Static Or BindingFlags.Instance)))
                If validation.AllowInternalMembers(fieldType) Then
                    bindingAttr = (bindingAttr Or BindingFlags.NonPublic)
                End If
                Dim field As FieldInfo = fieldType.GetField(strArray(i), bindingAttr)
                If (Not field Is Nothing) Then
                    fieldType = field.FieldType
                Else
                    Dim property As PropertyInfo = fieldType.GetProperty(strArray(i), bindingAttr)
                    If (Not [property] Is Nothing) Then
                        fieldType = [property].PropertyType
                    Else
                        [error] = New ValidationError(String.Format(CultureInfo.CurrentCulture, Messages.UpdateUnknownFieldOrProperty, New Object() { strArray(i) }), 390)
                        [error].UserData.Item("ErrorObject") = Me
                        validation.AddError([error])
                        Return False
                    End If
                End If
            Next i
            Return True
        End Function


        ' Properties
        Public ReadOnly Property Path As String
            Get
                Return Me.attributePath
            End Get
        End Property

        Public ReadOnly Property Target As RuleAttributeTarget
            Get
                Return Me.attributeTarget
            End Get
        End Property


        ' Fields
        Private attributePath As String
        Private attributeTarget As RuleAttributeTarget
    End Class
End Namespace

